#include "ExchRepoProcess.h"

#include <core/Utility.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSFIModel.h>
#include <qbprotocol/include/rdProto.h>

using namespace qb;

namespace {
#define Reg_Func(ID)                            \
  qbBase::getMessageBond()->RegisterDecodeFunc( \
      ID, qbmsg::exchangerepo::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QB_MM_EX_PRICE_QUERY_V2, xxMMListAck_c);
    DelPtr(E_FID_QB_MM_PRICE_PUSH_V3, xxMMListAck_c);
    default:
      break;
  }
  return toDel;
}
}  // namespace

void qbmsg::exchangerepo::InitDecodeFuncs() {
  Reg_Func(E_FID_QB_MM_EX_PRICE_QUERY_V2);
  Reg_Func(E_FID_QB_MM_PRICE_PUSH_V3);
  Reg_Func(E_FID_QB_MM_PRICE_PUSH_CANCEL_V3);
}

void qbmsg::exchangerepo::EncodeFunc(qb::proto::Message& msg,
                                     qb::SSRequestMsg* req) {
  switch (req->m_FuncID) {
    case E_FID_QB_MM_EX_PRICE_QUERY_V2:
    case E_FID_QB_MM_PRICE_PUSH_V3:
      // 	case E_FID_QB_MM_PRICE_PUSH_CANCEL_V3:
      {
        qb::proto::VariantList sublist;
        xxMMListQuery_c* pdata = (xxMMListQuery_c*)req->m_pRequest;
        for (std::list<xMMReq_c>::const_iterator it = pdata->m_List.begin();
             it != pdata->m_List.end(); ++it) {
          qb::proto::VariantMap submap;
          submap.setString("RateKey", it->m_RateKey);
          submap.setString("RateID", it->m_RateID);
          submap.setString("ListedMarket", it->m_ListedMarket);
          sublist.push_back(submap);
        }
        msg.SetList("List", sublist);
        break;
      }
    default:
      break;
  }
}

void* qbmsg::exchangerepo::ExtracFunc(int func, const ProtoMessage& msg,
                                      void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  switch (func) {
    case E_FID_QB_MM_EX_PRICE_QUERY_V2: {
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xxMMListAck_c* ptr = new xxMMListAck_c;
      if (!ptr) return nullptr;

      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        const ProtoMap& msgmap = *it;
        xMMPrice_c unit;
        FIELDCOPY(unit.m_RateKey, CParserTool::GetString(msgmap, "rk"));
        FIELDCOPY(unit.m_ListedMarket, CParserTool::GetString(msgmap, "lm"));
        FIELDCOPY(unit.m_Price, CParserTool::GetString(msgmap, "pri"));
        FIELDCOPY(unit.m_Chg, CParserTool::GetString(msgmap, "chg"));
        FIELDCOPY(unit.m_Open, CParserTool::GetString(msgmap, "op"));
        FIELDCOPY(unit.m_High, CParserTool::GetString(msgmap, "hp"));
        FIELDCOPY(unit.m_Low, CParserTool::GetString(msgmap, "lp"));
        FIELDCOPY(unit.m_Prev, CParserTool::GetString(msgmap, "pc"));
        FIELDCOPY(unit.m_Vol, CParserTool::GetString(msgmap, "vol"));
        FIELDCOPY(unit.m_Weight, CParserTool::GetString(msgmap, "wgt"));
        unsigned int time = 0;
        msgmap.getUint32("tm", time);
        unit.m_Time = time;
        ptr->m_List.push_back(unit);
      }
      return ptr;
      break;
    }
    case E_FID_QB_MM_PRICE_PUSH_V3: {
      static const char* rk = "1";
      static const char* lm = "2";
      static const char* pri = "3";
      static const char* chg = "4";
      static const char* op = "5";
      static const char* hp = "6";
      static const char* lp = "7";
      static const char* pc = "8";
      static const char* vol = "9";
      static const char* tm = "10";
      static const char* wgt = "11";

      qb::base::msg::Raw raw;
      if (!msg.GetRaw("list", raw)) return nullptr;

      xxMMListAck_c* ptr = new xxMMListAck_c;
      if (!ptr) return nullptr;

      qb::proto::VariantTableDecoder msglist;
      if (!msglist.decode((const char*)raw.Data, raw.Length)) return ptr;

      for (auto it = msglist.begin(); it != msglist.end(); ++it) {
        xMMPrice_c unit;
        const qb::proto::VariantRecord* msgmap = *it;
        FIELDCOPY(unit.m_RateKey, CParserTool::GetString(msgmap, rk));
        FIELDCOPY(unit.m_ListedMarket, CParserTool::GetString(msgmap, lm));
        FIELDCOPY(unit.m_Price, CParserTool::GetString(msgmap, pri));
        FIELDCOPY(unit.m_Chg, CParserTool::GetString(msgmap, chg));
        FIELDCOPY(unit.m_Open, CParserTool::GetString(msgmap, op));
        FIELDCOPY(unit.m_High, CParserTool::GetString(msgmap, hp));
        FIELDCOPY(unit.m_Low, CParserTool::GetString(msgmap, lp));
        FIELDCOPY(unit.m_Prev, CParserTool::GetString(msgmap, pc));
        FIELDCOPY(unit.m_Vol, CParserTool::GetString(msgmap, vol));
        uint64_t time = 0;
        msgmap->getUint64(tm, time);
        unit.m_Time = time;
        FIELDCOPY(unit.m_Weight, CParserTool::GetString(msgmap, wgt));
        ptr->m_List.push_back(unit);
      }
      return ptr;
      break;
    }
    default:
      break;
  }

  return nullptr;
}
